/*
MIT License

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo/loom
*/

#include "simodo/interpret/builtins/modules/LexicalParametersModule.h"
#include "simodo/variable/VariableSetWrapper.h"
#include "simodo/inout/convert/functions.h"

#include <cassert>

// #include <iostream>

namespace simodo::interpret::builtins
{
    namespace
    {
        variable::Value clearMarkups(variable::Module_interface * host, const variable::VariableSetWrapper & )
        {
            // std::cout << "clearMarkups" << std::endl;

            assert(host != nullptr);
            LexicalParametersModule & lex = *(static_cast<LexicalParametersModule *>(host));
            lex().markups.clear();

            return u"";
        }

        variable::Value addMarkup(variable::Module_interface * host, const variable::VariableSetWrapper & args)
        {
            // std::cout << "addMarkup" << std::endl;

            std::u16string start = get<std::u16string>(args[0].origin().variant());
            std::u16string end = get<std::u16string>(args[1].origin().variant());
            std::u16string ignore_sign = get<std::u16string>(args[2].origin().variant());
            int64_t type = get<int64_t>(args[3].origin().variant());

            assert(host != nullptr);
            LexicalParametersModule & lex = *(static_cast<LexicalParametersModule *>(host));
            lex().markups.push_back({start, end, ignore_sign, static_cast<inout::LexemeType>(type)});

            return u"";
        }

        variable::Value clearMasks(variable::Module_interface * host, const variable::VariableSetWrapper & )
        {
            // std::cout << "clearMasks" << std::endl;

            assert(host != nullptr);
            LexicalParametersModule & lex = *(static_cast<LexicalParametersModule *>(host));
            lex().masks.clear();

            return u"";
        }

        variable::Value addMask(variable::Module_interface * host, const variable::VariableSetWrapper & args)
        {
            // std::cout << "addMask" << std::endl;

            std::u16string chars = get<std::u16string>(args[0].origin().variant());
            int64_t type = get<int64_t>(args[1].origin().variant());
            int64_t system = get<int64_t>(args[2].origin().variant());

            assert(host != nullptr);
            LexicalParametersModule & lex = *(static_cast<LexicalParametersModule *>(host));
            lex().masks.push_back({chars, static_cast<inout::LexemeType>(type), static_cast<inout::number_system_t>(system)});

            return u"";
        }

        variable::Value setNationalAlphabet(variable::Module_interface * host, const variable::VariableSetWrapper & args)
        {
            // std::cout << "setNationalAlphabet" << std::endl;

            std::u16string national_alphabet = get<std::u16string>(args[0].origin().variant());

            assert(host != nullptr);
            LexicalParametersModule & lex = *(static_cast<LexicalParametersModule *>(host));
            lex().national_alphabet = national_alphabet;

            return u"";
        }

        variable::Value setIdExtraSymbols(variable::Module_interface * host, const variable::VariableSetWrapper & args)
        {
            // std::cout << "setIdExtraSymbols" << std::endl;

            std::u16string id_extra_symbols = get<std::u16string>(args[0].origin().variant());

            assert(host != nullptr);
            LexicalParametersModule & lex = *(static_cast<LexicalParametersModule *>(host));
            lex().id_extra_symbols = id_extra_symbols;

            return u"";
        }

        variable::Value setNationalLettersUse(variable::Module_interface * host, const variable::VariableSetWrapper & args)
        {
            // std::cout << "setNationalLettersUse" << std::endl;

            bool may_national_letters_use = get<bool>(args[0].origin().variant());

            assert(host != nullptr);
            LexicalParametersModule & lex = *(static_cast<LexicalParametersModule *>(host));
            lex().may_national_letters_use = may_national_letters_use;

            return u"";
        }

        variable::Value setNationalLettersMix(variable::Module_interface * host, const variable::VariableSetWrapper & args)
        {
            // std::cout << "setNationalLettersMix" << std::endl;

            bool may_national_letters_mix = get<bool>(args[0].origin().variant());

            assert(host != nullptr);
            LexicalParametersModule & lex = *(static_cast<LexicalParametersModule *>(host));
            lex().may_national_letters_mix = may_national_letters_mix;

            return u"";
        }

        variable::Value setCaseSensitive(variable::Module_interface * host, const variable::VariableSetWrapper & args)
        {
            // std::cout << "setCaseSensitive" << std::endl;

            bool is_case_sensitive = get<bool>(args[0].origin().variant());

            assert(host != nullptr);
            LexicalParametersModule & lex = *(static_cast<LexicalParametersModule *>(host));
            lex().is_case_sensitive = is_case_sensitive;

            return u"";
        }

        variable::Value setNewLineSubstitution(variable::Module_interface * host, const variable::VariableSetWrapper & args)
        {
            // std::cout << "setNewLineSubstitution" << std::endl;

            std::u16string nl_substitution = get<std::u16string>(args[0].origin().variant());

            assert(host != nullptr);
            LexicalParametersModule & lex = *(static_cast<LexicalParametersModule *>(host));
            lex().nl_substitution = nl_substitution;

            return u"";
        }

    }

    LexicalParametersModule::LexicalParametersModule(inout::LexicalParameters &lex)
        : _lex(lex)
    {
        // std::cout << "LexicalParametersModule" << std::endl;
    }

    LexicalParametersModule::~LexicalParametersModule()
    {
        // std::cout << "~LexicalParametersModule" << std::endl;
    }

    using namespace simodo::variable;

    variable::Object LexicalParametersModule::instantiate(std::shared_ptr<variable::Module_interface> module_host)
    {
        // std::cout << "instantiate" << std::endl;

        return {{
            {u"clearMarkups", {ValueType::Function, Object {{
                {u"@", ExternalFunction {{module_host}, clearMarkups}},
                {{}, ValueType::Null},
            }}}},
            {u"addMarkup", {ValueType::Function, Object {{
                {u"@", ExternalFunction {{module_host}, addMarkup}},
                {{}, ValueType::Null},
                {u"start", ValueType::String},
                {u"end", ValueType::String},
                {u"ignore_sign", ValueType::String},
                {u"type", ValueType::Int},
            }}}},
            {u"clearMasks", {ValueType::Function, Object {{
                {u"@", ExternalFunction {{module_host}, clearMasks}},
                {{}, ValueType::Null},
            }}}},
            {u"addMask", {ValueType::Function, Object {{
                {u"@", ExternalFunction {{module_host}, addMask}},
                {{}, ValueType::Null},
                {u"chars", ValueType::String},
                {u"type", ValueType::Int},
                {u"system", ValueType::Int},
            }}}},
            {u"setNationalAlphabet", {ValueType::Function, Object {{
                {u"@", ExternalFunction {{module_host}, setNationalAlphabet}},
                {{}, ValueType::Null},
                {u"national_alphabet", ValueType::String},
            }}}},
            {u"setIdExtraSymbols", {ValueType::Function, Object {{
                {u"@", ExternalFunction {{module_host}, setIdExtraSymbols}},
                {{}, ValueType::Null},
                {u"id_extra_symbols", ValueType::String},
            }}}},
            {u"setNationalLettersUse", {ValueType::Function, Object {{
                {u"@", ExternalFunction {{module_host}, setNationalLettersUse}},
                {{}, ValueType::Null},
                {u"may_national_letters_use", ValueType::Bool},
            }}}},
            {u"setNationalLettersMix", {ValueType::Function, Object {{
                {u"@", ExternalFunction {{module_host}, setNationalLettersMix}},
                {{}, ValueType::Null},
                {u"may_national_letters_mix", ValueType::Bool},
            }}}},
            {u"setCaseSensitive", {ValueType::Function, Object {{
                {u"@", ExternalFunction {{module_host}, setCaseSensitive}},
                {{}, ValueType::Null},
                {u"is_case_sensitive", ValueType::Bool},
            }}}},
            {u"setNewLineSubstitution", {ValueType::Function, Object {{
                {u"@", ExternalFunction {{module_host}, setNewLineSubstitution}},
                {{}, ValueType::Null},
                {u"is_case_sensitive", ValueType::String},
            }}}},
            {u"LexemeType", Object {{
                {u"Id", static_cast<int64_t>(inout::LexemeType::Id)},
                {u"Empty", static_cast<int64_t>(inout::LexemeType::Empty)},
                {u"Error", static_cast<int64_t>(inout::LexemeType::Error)},
                {u"Number", static_cast<int64_t>(inout::LexemeType::Number)},
                {u"Comment", static_cast<int64_t>(inout::LexemeType::Comment)},
                {u"Compound", static_cast<int64_t>(inout::LexemeType::Compound)},
                {u"Annotation", static_cast<int64_t>(inout::LexemeType::Annotation)},
                {u"Punctuation", static_cast<int64_t>(inout::LexemeType::Punctuation)},
                {u"NewLine", static_cast<int64_t>(inout::LexemeType::NewLine)},
            }}},
        }};
    }

    // variable::ModuleFactory_interface* LexicalParametersModule::factory()
    // {
    //     // std::cout << "factory" << std::endl;

    //     return nullptr;
    // }
}
